package de.karlNet.sambamanager.tests.groups;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.UUID;

import javax.naming.NamingException;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import de.karlNet.sambamanager.ldapController.LdapMemberOfTree;
import de.karlNet.sambamanager.ldapController.OriginalLdapTree;
import de.karlNet.sambamanager.ldapController.commands.macros.CreateGroupMacro;
import de.karlNet.sambamanager.ldapController.commands.macros.CreateUserMacro;
import de.karlNet.sambamanager.ldapController.commands.macros.ExtractGroupMacro;
import de.karlNet.sambamanager.ldapModel.LdapGroup;
import de.karlNet.sambamanager.ldapModel.LdapUser;
import de.karlNet.sambamanager.ldapModel.dto.LdapGroupCreationDTO;
import de.karlNet.sambamanager.ldapModel.dto.LdapUserCreationDTO;
import de.karlNet.sambamanager.tests.SambamanagerBaseTest;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext.xml" })
public class ExtractGroupFromUser extends SambamanagerBaseTest {
	@Autowired
	private CreateUserMacro createUserMacro;

	@Autowired
	private ExtractGroupMacro extractGroupMacro;

	@Autowired
	private CreateGroupMacro createGroupMacro;
	
	@Autowired
	private OriginalLdapTree originalLdapTree;
	
	@Autowired
	private LdapMemberOfTree ldapMemberOfTree;

	private boolean containsDN(String dn, List<String> ldapObjects) {
		for (String ldapObject : ldapObjects) {
			if (ldapObject.toLowerCase().equals(dn.toLowerCase())) {
				return true;
			}
		}
		return false;
	}
	
	@Test
	public void testGroupExtraction() throws UnsupportedEncodingException, NamingException {
		String username = UUID.randomUUID().toString();
		LdapUserCreationDTO ldapUserCreationDTO = new LdapUserCreationDTO();
		LdapUser ldapUser = ldapUserCreationDTO.getLdapUser();
		ldapUser.setCn(username);
		String userDn = "cn=" + username + this.getNestInDN();
		ldapUser.setDn(userDn);
		ldapUser.setUsername(username);
		String password = "p4ssw0rd!";
		ldapUser.setPassword(password);
		ldapUser.setFirstname(UUID.randomUUID().toString());
		ldapUser.setLastname(UUID.randomUUID().toString());
		this.createUserMacro.createUser(ldapUserCreationDTO);
		
		String cnOfGroup1 = UUID.randomUUID().toString();
		String group1Dn = "cn=" + cnOfGroup1 + this.getNestInDN();
		{
			LdapGroupCreationDTO creationDTO = new LdapGroupCreationDTO();
			creationDTO.getLdapGroup().setCn(cnOfGroup1);
			
			creationDTO.getLdapGroup().setDn(group1Dn);
			creationDTO.getMembers().add(ldapUser);
			this.createGroupMacro.createGroup(creationDTO);
		}
		
		String group2Cn = UUID.randomUUID().toString();
		String group2Dn = "cn=" + group2Cn + this.getNestInDN();
		{
			LdapGroupCreationDTO creationDTO = new LdapGroupCreationDTO();
			creationDTO.getLdapGroup().setCn(group2Cn);
			creationDTO.getLdapGroup().setDn(group2Dn);
			creationDTO.getMembers().add(ldapUser);
			this.createGroupMacro.createGroup(creationDTO);
		}
		
		ldapUser = (LdapUser) this.originalLdapTree.getObject(userDn);
		String extractedGroupName =  UUID.randomUUID().toString();
		String dnOfExtractedGroup = "cn=" + extractedGroupName + this.getNestInDN();
		LdapGroup extractedGroup = new LdapGroup(extractedGroupName, dnOfExtractedGroup);
		this.extractGroupMacro.extractGroupFromUser(ldapUser, extractedGroup);
		
		this.testValidility(dnOfExtractedGroup, ldapUser, group1Dn, group2Dn);
	}
	
	private void testValidility(String dnOfExtractedGroup, LdapUser ldapUser, String group1Dn, String group2Dn) {
		LdapGroup extractedGroupLdapObject = (LdapGroup)this.originalLdapTree.getObject(dnOfExtractedGroup);
		Assert.assertTrue("object not found", extractedGroupLdapObject!=null);
		
		Assert.assertTrue("group1 not found" ,this.containsDN(group1Dn, extractedGroupLdapObject.getMembers()));
		Assert.assertTrue("group2 not found" ,this.containsDN(group2Dn, extractedGroupLdapObject.getMembers()));
		
		ldapUser = (LdapUser) this.originalLdapTree.getObject(ldapUser.getDn());
		Assert.assertFalse("group1 listed as memberof in user", this.containsDN(group1Dn, ldapUser.getMemberOf()));
		Assert.assertFalse("group2 listed as memberof in user", this.containsDN(group2Dn, ldapUser.getMemberOf()));
		Assert.assertTrue("extracted group not listed in user", this.containsDN(dnOfExtractedGroup, ldapUser.getMemberOf()));
	}
	
	@Test
	public void testGroupExtractionWithApplyingToAll() throws UnsupportedEncodingException {
		String username = "11-" + UUID.randomUUID().toString();
		LdapUserCreationDTO ldapUserCreationDTO1 = new LdapUserCreationDTO();
		LdapUser ldapUser1 = ldapUserCreationDTO1.getLdapUser();
		ldapUser1.setCn(username);
		String userDn1 = "cn=" + username + this.getNestInDN();
		ldapUser1.setDn(userDn1);
		ldapUser1.setUsername(username);
		String password1 = "p4ssw0rd!";
		ldapUser1.setPassword(password1);
		ldapUser1.setFirstname(UUID.randomUUID().toString());
		ldapUser1.setLastname(UUID.randomUUID().toString());
		this.createUserMacro.createUser(ldapUserCreationDTO1);
		
		String username2 = "22-" + UUID.randomUUID().toString();
		LdapUserCreationDTO ldapUserCreationDTO2 = new LdapUserCreationDTO();
		LdapUser ldapUser2 = ldapUserCreationDTO2.getLdapUser();
		ldapUser2.setCn(username2);
		String userDn2 = "cn=" + username2 + this.getNestInDN();
		ldapUser2.setDn(userDn2);
		ldapUser2.setUsername(username2);
		String password2 = "p4ssw0rd!";
		ldapUser2.setPassword(password2);
		ldapUser2.setFirstname(UUID.randomUUID().toString());
		ldapUser2.setLastname(UUID.randomUUID().toString());
		this.createUserMacro.createUser(ldapUserCreationDTO2);
		
		String cnOfGroup1 = UUID.randomUUID().toString();
		String group1Dn = "cn=" + cnOfGroup1 + this.getNestInDN();
		{
			LdapGroupCreationDTO creationDTO = new LdapGroupCreationDTO();
			creationDTO.getLdapGroup().setCn(cnOfGroup1);
			
			creationDTO.getLdapGroup().setDn(group1Dn);
			creationDTO.getMembers().add(ldapUser1);
			creationDTO.getMembers().add(ldapUser2);
			this.createGroupMacro.createGroup(creationDTO);
		}
		
		String group2Cn = UUID.randomUUID().toString();
		String group2Dn = "cn=" + group2Cn + this.getNestInDN();
		{
			LdapGroupCreationDTO creationDTO = new LdapGroupCreationDTO();
			creationDTO.getLdapGroup().setCn(group2Cn);
			creationDTO.getLdapGroup().setDn(group2Dn);
			creationDTO.getMembers().add(ldapUser1);
			creationDTO.getMembers().add(ldapUser2);
			this.createGroupMacro.createGroup(creationDTO);
		}
		ldapMemberOfTree.reset();
		ldapUser1 = (LdapUser) this.originalLdapTree.getObject(userDn1);
		ldapUser2 = (LdapUser) this.originalLdapTree.getObject(userDn2);
		String extractedGroupName = UUID.randomUUID().toString();
		String dnOfExtractedGroup = "cn=" + extractedGroupName + this.getNestInDN();
		LdapGroup extractedGroup = new LdapGroup(extractedGroupName, dnOfExtractedGroup);
		this.extractGroupMacro.extractGroupFromUserAndModifyAllUsers(ldapUser1, extractedGroup);
		this.testValidility(dnOfExtractedGroup, ldapUser1, group1Dn, group2Dn);
		this.testValidility(dnOfExtractedGroup, ldapUser2, group1Dn, group2Dn);
	}
}
